package com.chenyuan.http;


import com.chenyuan.tools.date.TimeUnit;
import org.testng.annotations.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @ClassName: test
 * @Author: 陈元
 * @Description:
 * @CreateDate: 2024/7/19 20:33
 * @Version: 1.0
 * @E-mail:1765065492@qq.com
 * @Link:https://github.com/1765065492
 */
public class test {

    @Test
    public void requestS() {
        EasyResponse response = EasyHttp.requst("https://www.baidu.com/s?ie=UTF-8&wd=test");
        System.out.println(response.getResponseBodyText());
    }

    @Test
    public void requestPcsearch() {
        EasyResponse response = EasyHttp.requst(RequestType.POST, "https://ug.baidu.com/mcp/pc/pcsearch", null,
                MessageType.JSON, "{\"invoke_info\":{\"pos_1\":[{}],\"pos_2\":[{}],\"pos_3\":[{}]}}");
        System.out.println(response.getResponseBodyText());
    }

    //接口协议
    //接口协议可通过类中的“getProtocol()”和“setProtocol(String)”方法进行获取和设置，若未对接口协议进行设置，则默认为“http://”
    @Test
    public void protocolTest() {
        InterfaceInfo ii = new InterfaceInfo();
        System.out.println(ii.getProtocol()); // 输出：http://
        ii.setProtocol("ftp://");
        System.out.println(ii.getProtocol()); // 输出：ftp://
    }

    // 主机地址
    //主机地址表示接口请求的地址，该地址可以是域名，也可以是IP地址，可通过类中的“getHost()”和“setHost(String)”方法进行获取和设置，若未设置主机地址，则默认为“127.0.0.1”
    @Test
    public void hostTest() {
        InterfaceInfo ii = new InterfaceInfo();
        System.out.println(ii.getHost()); // 输出：127.0.0.1
        ii.setHost("10.10.10.10");
        System.out.println(ii.getHost()); // 输出：10.10.10.10
    }

    //端口号
    //请求接口的端口号可通过“getPort()”和“setPort(int)”方法进行读取和设置，其默认值为80，其数值的设置范围为0~65535之间，当传入的数字超出该范围，则不进行设置
    @Test
    public void portTest() {
        InterfaceInfo ii = new InterfaceInfo();
        System.out.println(ii.getPort()); // 输出：80
        ii.setPort(8080);
        System.out.println(ii.getPort()); // 输出：8080
    }

    //接口路径
    //接口路径可通过“getPath()”和“setPath(String)”方法进行读取和设置接口路径。当设置的接口路径第一位字符非“/”符号是，则默认自动将其补上；若接口路径最后一位字符为“/”符号是，则默认去除该符号
    @Test
    public void pathTest() {
        InterfaceInfo ii = new InterfaceInfo();
        ii.setPath("a/b/c/");
        System.out.println(ii.getPath()); // 输出：/a/b/c
    }

    //接口请求参数
    //接口请求参数可通过“getParamMap()”方法，获取到添加的接口参数。参数的设置方法有三种形式：
    //
    //addParams(Map<String, String>)：按照键值对集合形式添加，其键为参数名，值为参数内容
    //addParam(String, String)：单个参数逐个添加
    //addParam(String)：按照url对参数的表达式进行添加，其形式为“参数1=数值1&参数2=数值2&...”。表达式的判断正则为“[\?？]?\w+=\w*(&\w+=\w*)*”，表达式第一位允许以“?”开头，程序会默认将其去除，之后的参数将按照“&”符号对每个参数进行切分，之后再按照“=”符号分割键值
    //需要注意的是，每次调用添加参数方法时，其将不会覆盖之前已有的参数，若需要重新设置参数内容，则需要调用“clearParam()”方法，清除原有的所有参数
    @Test
    public void paramTest() {
        Map<String, String> paramMap = new HashMap<>(16);
        paramMap.put("k1", "v1");
        paramMap.put("k2", "v2");

        InterfaceInfo ii = new InterfaceInfo();
        ii.addParams(paramMap);
        System.out.println(ii.toUrlString()); // 输出：http://127.0.0.1?k1=v1&k2=v2
        ii.addParam("k3", "v3");
        System.out.println(ii.toUrlString()); // 输出：http://127.0.0.1?k1=v1&k2=v2&k3=v3
        ii.addParam("?k4=v4&k5=v5");
        System.out.println(ii.toUrlString()); // 输出：http://127.0.0.1?k1=v1&k2=v2&k3=v3&k4=v4&k5=v5

        paramMap = ii.clearParam();
        System.out.println(ii.toUrlString()); // 输出：http://127.0.0.1
        System.out.println(paramMap); // 输出：{k3=v3, k4=v4, k5=v5, k1=v1, k2=v2}
    }

    //url解析
    //类中允许直接通过“analysisUrl(String)”方法，传入接口的url来添加接口的基本信息，以简化对接口信息的添加难度。
    // 方法允许只传入url的部分信息，例如只传入协议号与主机，或者只传入端口号与参数，但每个信息的分隔符号必须严格按照url的格式进行编写，
    // 例如，当只需要设置协议、端口与参数时，可按照以下写法：

    //url解析的顺序为：
    //
    //参数→协议→接口地址→端口号→主机地址
    //
    //方法对传入的内容通过判断url所有的特征符号，按照以上的解析顺序，逐个解析并存储，剩余的内容则是主机地址，用于识别的特征符号如下：
    //
    //参数：以“?”符号为分界，将其后的内容识别为参数
    //协议：以“://”符号为分界，将其前的内容识别为协议
    //接口地址：以“/”符号为分界，将其后的内容识别为接口地址
    //端口号：以“:”符号为分界，将其后的内容识别为端口号
    @Test
    public void analysisUrlTest() {
        InterfaceInfo ii = new InterfaceInfo();
        ii.analysisUrl("ftp://:8812?a=1&b=2&c=3");
        System.out.println(ii.toUrlString()); // 输出：ftp://127.0.0.1:8812?a=1&b=2&c=3
    }
    //接口请求类型
    //接口请求类型（request type）可通过“getRequestType()”和“setRequestType(RequestType)”方法进行获取和设置，
    // 其方法中的“RequestType”为请求类型枚举类，其中枚举了常用的接口请求类型，通过传入枚举类，以便于对传入的参数进行控制
    @Test
    public void requestTypeTest() {
        InterfaceInfo ii = new InterfaceInfo();
        ii.setRequestType(RequestType.POST);
        System.out.println(ii.getRequestType()); // 输出：POST
    }
    //请求体
    //请求体可通过“getBody()”方法获取设置的请求体参数，由于请求体设置除参数外，还需要指定相应的请求体格式，
    // 用于在请求接口时方便添加相应的请求头，故其设置的方法为“setBody(MessageType, String)”，其中，“MessageType”为消息类型枚举类，
    // 其中包含常用了消息类型（如json格式），以及消息类型对应的请求头头内容。若请求体为json、xml、html格式的内容，还可以使用“setBody(String)”方法，
    // 该方法可自动识别上述的三种格式，但由于请求工具允许定义公式，导致请求体包含占位符时，可能会出现识别不准确的情况，建议手动进行添加。
    //
    //为方便请求工具调用，“getBody()”方法返回的内容为键值对的形式类对象（Entry<MessageType, String>），
    // 其键为设置的消息类型枚举，值为相应的请求体，在输出时，可通过类中的get方法，分别获取键值的内容//   @Test
//    public void bodyTest() {
//        InterfaceInfo ii = new InterfaceInfo();
//        ii.setBody(MessageType.HTML, "<html></html>");
//        Entry<MessageType, String> content = ii.getBody();
//        System.out.println("键：" + content.getKey()); // 输出：HTML
//        System.out.println("值：" + content.getValue()); // 输出：<html></html>
//
//        ii.setBody("{\"a\":\"b\"}");
//        content = ii.getBody();
//        System.out.println("键：" + content.getKey()); // 输出：JSON
//        System.out.println("值：" + content.getValue()); // 输出：{"a":"b"}
//    }


    //请求头
    //请求头可通过“getRequestHeaderMap()”方法,获取到已添加的请求头信息，其返回内容为Map集合其键为请求头的参数名称，值为请求头的名称对应的内容。添加请求头有以下两种方法：
    //
    //addRequestHeaderMap(Map<String, String>)：一次性添加一组请求头
    //addRequestHeader(String, String)：添加单个请求头
    //由于工具内部调用OkHttp工具作为接口请求的底层调用方法，故常用的请求头可无需添加，在请求时其会自动带入，在添加请求头时，只需要添加接口中特别的请求头即可。
    // 需要注意的是，调用添加请求头方法后，其新添加的数据不会覆盖已有的请求头内容，若需要修改，可调用“clearRequestHeaderMap()”方法清空已有的请求头后，再重新进行添加

    @Test
    public void requestHeaderTest() {
        Map<String, String> requestHeaderMap = new HashMap<>(16);
        requestHeaderMap.put("k1", "v1");
        requestHeaderMap.put("k2", "v2");

        InterfaceInfo ii = new InterfaceInfo();
        ii.addRequestHeaderMap(requestHeaderMap);
        System.out.println(ii.getRequestHeaderMap()); // 输出：{k1=v1, k2=v2}
        ii.addRequestHeader("k3", "v3");
        System.out.println(ii.getRequestHeaderMap()); // 输出：{k3=v3, k1=v1, k2=v2}
        requestHeaderMap = ii.clearRequestHeaderMap();
        System.out.println(ii.getRequestHeaderMap()); // 输出：{}
        System.out.println(requestHeaderMap); // 输出：{k3=v3, k1=v1, k2=v2}
    }

    //请求cookie
    //当接口请求需要带cookie时，可通过“addCookie(String, String)”等一系列的添加方法，对接口添加cookie。
    //
    //在添加cookie时，可通过cookie表达式式对cookie内容进行添加，即使用“cookie名称1=cookie值1;cookie名称2=cookie值2;...”的形似，
    // 调用“addCookie(String)”方法进行添加，同样，亦可调用“getCookieExpression()”方法以表达式的方法返回已添加的cookie，
    // 其他添加、清除、返回cookie的方法与请求头类似，此处不再过多介绍。

    @Test
    public void cookieTest() {
        Map<String, String> cookieMap = new HashMap<>(16);
        cookieMap.put("k1", "v1");
        cookieMap.put("k2", "v2");

        InterfaceInfo ii = new InterfaceInfo();
        ii.addCookies(cookieMap);
        System.out.println(ii.getCookieMap()); // 输出：{k1=v1, k2=v2}
        ii.addCookie("k3", "v3");
        ii.addCookie("k4=v4;k=5;v=5");
        System.out.println(ii.getCookieExpression()); // 输出：k1=v1;k2=v2;k3=v3;k4=v4;k5=v5
        cookieMap = ii.clearCookies();
        System.out.println(ii.getCookieMap()); // 输出：{}
        System.out.println(cookieMap); // 输出：{k3=v3, k1=v1, k2=v2, k4=v4, k5=v5}
    }


    // 接口超时时间
    //由于部分接口请求时间较长，则需要对接口的请求时间进行设置，避免接口返回前被程序判定为超时。设置接口超时时间的方法有两个，分别为：
    //
    //setConnectTime(long, TimeUnit)：根据数字与时间单位，设置其相应的接口超时时间，支持的时间单位有：年、月、周、日、时、分、秒、毫秒。
    // 若使用数字与单位的方法设置接口超时时间时，需要注意的，当单位使用“年”时，则按照365.25天进行计算；而使用“月”时，则以30.4375天进行计算（应该也没有接口会使用到这两个单位）
    //setConnectTime(String)：根据时间块表达式，设置接口超时时间，使用该方法设置的超时时间，最终存储时会被转换为毫秒值进行存储
    //时间块是由时间数字与单位拼凑而成的字符串，即1分钟可用“1min”来表示，当然，也可以直接写为“1分”，具体支持的单位可参考工具javadoc文档的“TimeUnit”内容。
    // 与通过数字和单位传入超时时间的方法不同的是，使用时间块可传入小数或者连续传入多个单位的时间，如传入“1.5min30s200ms”，表示1.5分钟+30秒+200毫秒（也就是2分钟200毫秒）。
    @Test
    public void connectTimeTest() {
        InterfaceInfo ii = new InterfaceInfo();
        ii.setConnectTime(10, TimeUnit.MINUTE);
        System.out.println(ii.getConnectTime()); // 输出：Entry [key=10, value=MINUTE]
        ii.setConnectTime("1.5mIn30秒");
        System.out.println(ii.getConnectTime()); // 输出：Entry [key=120000, value=MILLISECOND]
    }
    //响应体解析字符集
    //响应字符集在解析响应体内容时需要使用，根据设置的响应字符集，采用对应的字符集编码，在接口响应工具中，对响应体进行解析，以返回符合预期内容的响应体。
    // 可通过“getCharsetname()”和“setCharsetname(String)”方法获取和设置响应体字符集信息，默认情况下，响应字符集为“UTF-8”
 /*   @Test
    public void charsetnameTest() {
        InterfaceInfo ii = new InterfaceInfo();
        System.out.println(ii.getCharsetname()); // 输出：UTF-8
        ii.setCharsetname("GBK");
        System.out.println(ii.getCharsetname()); // 输出：GBK
    }*/
    //响应体格式
    //响应体格式可能根据不同的状态码，其格式可能不尽相同，甚至同一个状态码，由于请求报文内容不同，其响应体的格式也可能不同，为方便在接口响应工具中进行解析，
    // 故其响应体格式存储的方式为“HashMap<Integer, HashSet<MessageType>>”，其键为接口相应状态码，值为状态码对应的响应体格式。由于其存储方式比较复杂，
    // 故类中不提供直接返回所有的响应体格式的方式，只能通过“getResponseContentType(int)”方法，传入状态码，来获取相应状态码下的响应体内容格式集合。
    // 若想获取所有存储的响应体格式集合，可通过“getAllSaveState()”方法，获取到存储的所有状态码，之后遍历所有状态码，获取到相应的响应体格式即可。
    //
    //鉴于响应体的存储复杂程度，故其添加的方式也需要根据状态码进行添加，其方法为“addResponseContentTypeSet(int, MessageType...)”，
    // 为简化单个状态码的添加次数，方法传入消息格式的参数采用可变参数的形式，使其可接收若干个格式参数。若需要修改参数，可通过“clearResponseContentType(int)”方法，
    // 清空并接收原有的内容后，在外部进行修改，再重新添加至类中

    @Test
    public void responseContentTypeTest() {
        InterfaceInfo ii = new InterfaceInfo();
        ii.addResponseContentTypeSet(500, MessageType.JSON, MessageType.RAW);
        ii.addResponseContentTypeSet(200, MessageType.HTML, MessageType.XML);
        ii.addResponseContentTypeSet(404, MessageType.HTML);
        /*
         * 输出：
         * [RAW, JSON]
         * [HTML]
         * [XML, HTML]
         */
        ii.getAllSaveState().stream().map(ii::getResponseContentType).forEach(System.out::println);

        Set<MessageType> responseContentType = ii.clearResponseContentType(404);
        System.out.println(ii.getResponseContentType(404)); // 输出：[]
        System.out.println(responseContentType); // 输出：[HTML]
    }
    //断言规则
    //通过添加接口的断言规则，可在接口请求工具中，实现自动断言的功能。断言规则的添加有三种方法：
    //
    //addAssertRule(String)：添加单个断言规则
    //addAssertRule(HashMap<String, String>)：按照Map集合形式添加单个断言规则
    //addAllAssertRule(Collection<String>)：添加多个断言规则
    //其中，断言规则字符串为一串Json文本串，为保证断言规则的扩展性，故未对其Json字段及相应内容进行过多的限制，只判断Json串中是否包含“assertRegex”字段，若不存在该字段，则不对相应内容进行存储。虽然不对Json串做过多的限制，但在接口请求工具中，仅会根据特定的字段进行处理，建议参考“3.1 接口信息读取工具基类”中介绍的各个字段含义进行添加。
    //
    //添加断言规则后，可使用“getAssertRuleJson()”方法获取到存储的Json串内容，若需要修改，则可使用“claerAssertRuleJson()”方法，清空存储的断言规则后，再将修改后的断言规则集合添加至类中
   /* @Test
    public void assertRuleTest() {
        // 为简化输出，此处只添加两个字段
        Map<String, String> assertRuleMap = new HashMap<>(16);
        assertRuleMap.put(ReadInterfaceFromAbstract.JSON_ASSERT_ASSERT_REGEX, "a1");
        assertRuleMap.put(ReadInterfaceFromAbstract.JSON_ASSERT_PARAM_NAME, "a2");

        JSONObject json1 = new JSONObject();
        json1.put(ReadInterfaceFromAbstract.JSON_ASSERT_ASSERT_REGEX, "b1");
        json1.put(ReadInterfaceFromAbstract.JSON_ASSERT_PARAM_NAME, "b2");

        JSONObject json2 = new JSONObject();
        json2.put(ReadInterfaceFromAbstract.JSON_ASSERT_ASSERT_REGEX, "c1");
        json2.put(ReadInterfaceFromAbstract.JSON_ASSERT_PARAM_NAME, "c2");

        JSONObject json3 = new JSONObject();
        json3.put(ReadInterfaceFromAbstract.JSON_ASSERT_ASSERT_REGEX, "d1");
        json3.put(ReadInterfaceFromAbstract.JSON_ASSERT_PARAM_NAME, "d2");

        ArrayList<String> jsonTextList = new ArrayList<>();
        jsonTextList.add(json2.toJSONString());
        jsonTextList.add(json3.toJSONString());

        InterfaceInfo ii = new InterfaceInfo();
        ii.addAssertRule(json1.toJSONString());
        System.out.println(ii.getAssertRuleJson()); // 输出：[{"assertRegex":"b1","paramName":"b2"}]

        ii.clearAssertRuleJson();
        ii.addAssertRule(assertRuleMap);
        System.out.println(ii.getAssertRuleJson()); // 输出：[{"assertRegex":"a1","paramName":"a2"}]

        ii.clearAssertRuleJson();
        ii.addAllAssertRule(jsonTextList);
        System.out.println(ii.getAssertRuleJson()); // 输出：[{"assertRegex":"c1","paramName":"c2"}, {"assertRegex":"d1","paramName":"d2"}]
    }*/
    //提词规则
    //通过添加接口的提词规则，可在接口请求工具中，实现自动提词的功能，并将其提取到的内容存储在接口请求工具中，以便于后续接口的调用。提词规则的添加有三种方法：
    //
    //addExtractRule(String)：添加单个提词规则
    //addExtractRule(HashMap<String, String>)：按照Map集合形式添加单个提词规则
    //addAllExtractRule(Collection<String>)：添加多个提词规则
    //与断言规则类似，提词规则也未对Json串做过多的限制，只判断Json串中是否包含“saveName”字段，若不存在该字段，则不对相应内容进行存储。
    // 同样，对提词规则Json串的添加，可参考“3.1 接口信息读取工具基类”中介绍的各个字段含义进行添加。
    //
    //添加提词规则后，可使用“getExtractRuleJson()”方法获取到存储的Json串内容，若需要修改，则可使用“clearExtractRuleJson()”方法，
    // 清空存储的断言规则后，再将修改后的提词规则集合添加至类中
    /*@Test
    public void extractRuleTest() {
        // 为简化输出，此处只添加两个字段
        Map<String, String> extractRuleMap = new HashMap<>(16);
        extractRuleMap.put(ReadInterfaceFromAbstract.JSON_EXTRACT_SAVE_NAME, "a1");
        extractRuleMap.put(ReadInterfaceFromAbstract.JSON_EXTRACT_PARAM_NAME, "a2");

        JSONObject json1 = new JSONObject();
        json1.put(ReadInterfaceFromAbstract.JSON_EXTRACT_SAVE_NAME, "b1");
        json1.put(ReadInterfaceFromAbstract.JSON_EXTRACT_PARAM_NAME, "b2");

        JSONObject json2 = new JSONObject();
        json2.put(ReadInterfaceFromAbstract.JSON_EXTRACT_SAVE_NAME, "c1");
        json2.put(ReadInterfaceFromAbstract.JSON_EXTRACT_PARAM_NAME, "c2");

        JSONObject json3 = new JSONObject();
        json3.put(ReadInterfaceFromAbstract.JSON_EXTRACT_SAVE_NAME, "d1");
        json3.put(ReadInterfaceFromAbstract.JSON_EXTRACT_PARAM_NAME, "d2");

        ArrayList<String> jsonTextList = new ArrayList<>();
        jsonTextList.add(json2.toJSONString());
        jsonTextList.add(json3.toJSONString());

        InterfaceInfo ii = new InterfaceInfo();
        ii.addExtractRule(json1.toJSONString());
        System.out.println(ii.getExtractRuleJson()); // 输出：[{"saveName":"b1","paramName":"b2"}]

        ii.clearExtractRuleJson();
        ii.addExtractRule(extractRuleMap);
        System.out.println(ii.getExtractRuleJson()); // 输出：[{"saveName":"a1","paramName":"a2"}]

        ii.clearExtractRuleJson();
        ii.addAllExtractRule(jsonTextList);
        System.out.println(ii.getExtractRuleJson()); // 输出：[{"saveName":"c1","paramName":"c2"},{"saveName":"d1","paramName":"d2"}]
    }
*/
    //接口信息存储与读取工具
    //为方便对接口的信息的管理以后后续开发功能的扩展，工具将接口信息从接口请求工具中分出来，
    // 单独形成一套存储方式，以方便接口自动化和性能自动化的实施。为方便接口信息的读取，每个接口存储工具应有一套与之对应的接口信息读取工具，
    // 接口信息存储模板和接口信息读取工具可自行进行扩展，工具中也定义了一些基本的方法，供自定义的读取工具继承和实现。此处仅说明主要的方法，
    // 详细的模板说明，可参考Wiki中“接口模板”的所有内容。
    //
    //下面则以xml模板中读取接口信息的工具进行说明（假设已定义如下xml模板）

/*    <?xml version="1.0" encoding="UTF-8"?>
<interfaceInfo>
    <environments>
    <environment name='环境1'>https://192.168.1.1</environment>
    <environment name='环境2'>http://192.168.1.2:8888</environment>
    <environment name='环境3'>http://192.168.1.3:8888</environment>
  </environments>

  <interfaces>
    <interface name='接口1' path='a/b/c' type='post' />
    <interface name='接口2' environment='环境1' path='a/b/c' type='post' />
  </interfaces>
</interfaceInfo>
*/
    //接口信息读取工具基类
    //ReadInterfaceFromAbstract为所有读取工具扩展类的基类，在“com.auxiliary.http”包下，其中定义了每个读取工具必须要实现的方法
    /*File xmlFile = new File("xml文件.xml");
    ReadInterfaceFromAbstract inter = new ReadInterfaceFromXml(xmlFile)*/
   /* 主要方法如下：

    InterfaceInfo getInterface(String)：该方法用于获取在模板中存储的所有接口信息，在自行扩展的模板中，应通过该方法，尽量将指定接口的所有信息进行读取，形成接口信息类对象，以便于后续自动化工作的开展。调用该方法后，将返回一个接口信息类对象，在其中可对接口信息进行修改，亦可直接放在接口请求工具中进行接口请求
    // 获取接口信息类对象，对接口信息进行修改
    InterfaceInfo info = inter.getInterface("接口名");
    // 或直接对接口进行请求
    new EasyHttp().requst(inter.getInterface("接口名"));
    void clearInterfaceInfoCache()：该方法用于清除接口信息缓存，为快速读取接口信息，在接口信息读取类中建议使用缓存机制，将已读取的接口信息进行缓存，存至类的“interfaceMap”属性中，以方便后续再次调用到相应名称的接口时，能进行快速返回。但由于该机制不是强制使用，故该方法仅针对写有缓存机制的子类生效
    // 注意，interfaceMap为protected权限，只有继承基类后才能调用
    System.out.println(interfaceMap.size()); // 存在数据
    inter.clearInterfaceInfoCache();
    System.out.println(interfaceMap.size()); // 不存在数据*/
}
